package com.gylang.print.pdf.test.pdf;

import cn.hutool.core.util.StrUtil;
import com.gylang.print.pdf.test.TestConstant;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author gylang
 * data 2021/6/3
 */
public class SealPdf {

	private static final Pattern BEAN_FORMAT = Pattern.compile("\\{\\w+}");


	public static void main(String[] args) {

		// 直接生成
		directCreator();
//		try2Replace();
	}

	private static void directCreator() {

		try (PDDocument document = new PDDocument()) {

			PDRectangle pdRectangle = new PDRectangle(800, 600);
			PDPage page = new PDPage(pdRectangle);
			document.addPage(page);
			PDPageContentStream stream = new PDPageContentStream(document, page);


			// 背景图片
			PDImageXObject bgImg = PDImageXObject.createFromFileByContent(new File("E:\\test\\RuoYi-Vue-gylang-integration\\doc\\seal\\background.jpg"), document);
			float scale = 1f;
			stream.drawImage(bgImg, 20, 20, page.getBBox().getWidth() * scale, page.getBBox().getHeight() * scale);
			stream.restoreGraphicsState();

			// qrcode
			PDImageXObject qrcode = PDImageXObject.createFromFileByContent(new File("E:\\test\\RuoYi-Vue-gylang-integration\\doc\\seal\\generate.png"), document);
			stream.drawImage(qrcode, 80, 500, 80, 80);
			stream.restoreGraphicsState();

			// 文本
			PDType0Font font = PDType0Font.load(document, Files.newInputStream(Paths.get("C:\\Windows\\Fonts\\simhei.ttf")));
			// 开启文本输入
			stream.beginText();
			// 设置文本定位
			stream.setFont(font, 30);
			stream.newLineAtOffset(378, 459);
			// 文本输入
			stream.showText("全球GPBC冠军赛");
			stream.endText();

			stream.beginText();
			stream.newLineAtOffset(164, 400);
			stream.setFont(font, 20);
			stream.showText("邓良才");
			stream.endText();

			stream.beginText();
			stream.newLineAtOffset(164, 360);
			stream.setFont(font, 15);
			stream.showText("恭喜你获得本次全球养猪技能竞赛-GPBC(GOLDEN-PIG-BREED-CHAMPIONSHIP)冠军。");
			stream.endText();

			stream.beginText();
			stream.newLineAtOffset(164, 163);
			stream.setFont(font, 10);
			stream.showText("证书编号: 484FW5184FWAFAW564W");
			stream.endText();

			stream.beginText();
			stream.newLineAtOffset(451, 163);
			stream.setFont(font, 10);
			stream.showText("发证机构: 猪猪侠");
			stream.endText();

			stream.beginText();
			stream.newLineAtOffset(164, 130);
			stream.setFont(font, 10);
			stream.showText("证书有效期至: 2022年2月22日");
			stream.endText();

			stream.beginText();
			stream.newLineAtOffset(451, 130);
			stream.setFont(font, 10);
			stream.showText("发证日期: 2020年2月22日");
			stream.endText();



			// 结束文本写入
			// 印章
			PDImageXObject sealImg = PDImageXObject.createFromFileByContent(new File("E:\\test\\RuoYi-Vue-gylang-integration\\doc\\seal\\seal.png"), document);
			stream.drawImage(sealImg, 540, 130, 150, 150);
			stream.restoreGraphicsState();

			stream.close();
			document.save(TestConstant.PDF_BASE + "seal" + System.currentTimeMillis() + ".pdf");

		} catch (IOException e) {
			e.printStackTrace();
		}


	}

	private static void try2Replace() {
		try (PDDocument document = PDDocument.load(new FileInputStream(TestConstant.PDF_BASE + "pdf_template.pdf"))) {
//		try (PDDocument document = PDDocument.load(new FileInputStream(TestConstant.PDF_BASE + "seal1622709993530.pdf"))) {

			// 写入背景
			PDPage page = document.getPage(0);
			//原文出自【易百教程】，商业转载请联系作者获得授权，非商业请保留原文链接：https://www.yiibai.com/pdfbox/pdfbox_inserting_image.html


//			PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true);
//			writeBackground(document, page, contentStream);
//			contentStream.close();

			// 重新写入文本

			Map<String, Object> data = new HashMap<>();
			data.put("name", "全球GPBC冠军");
			data.put("userInfo", "猪猪侠");
			data.put("content", "恭喜你获得本次全球大型养猪技能竞赛-GPBC(GOLDEN-PIG-BREED-CHAMPIONSHIP)冠军。");

			// doc4j 占位替换
			StringBuilder codeOrg = new StringBuilder();
			data.put("code", "3124197423572389573293527412");
			data.put("org", "全球养猪修养协会");
			data.put("userInfo", "小猪佩奇");

			data.put("publish", "2022年2月22日");
			data.put("expire", "2020年2月22日");
			replace(page, document, data);

			document.save(TestConstant.PDF_BASE + "seal" + System.currentTimeMillis() + ".pdf");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void replace(PDPage page, PDDocument document, Map<String, Object> data) throws IOException {
		PDFStreamParser parser = new PDFStreamParser(page);
		parser.parse();
		List tokens = parser.getTokens();
		for (int j = 0; j < tokens.size(); j++) {
			Object next = tokens.get(j);
			if (next instanceof Operator) {
				Operator op = (Operator) next;
				//Tj and TJ are the two operators that display strings in a PDF
				if (op.getName().equals("Tj")) {
					// Tj takes one operator and that is the string to display so lets update that operator
					COSString previous = (COSString) tokens.get(j - 1);
					String string = previous.getString();
					if (BEAN_FORMAT.matcher(string).find()) {
						string = StrUtil.format(string, data);
					}
					previous.setValue(string.getBytes());
				} else if (op.getName().equals("TJ")) {
					COSArray previous = (COSArray) tokens.get(j - 1);
					for (int k = 0; k < previous.size(); k++) {
						Object arrElement = previous.getObject(k);
						if (arrElement instanceof COSString) {
							COSString cosString = (COSString) arrElement;
							String string = cosString.getString();
							if (BEAN_FORMAT.matcher(string).find()) {
								string = StrUtil.format(string, data);
							}
							cosString.setValue(string.getBytes());
						}
					}
				}
			}
		}
	}


	private static void writeBackground(PDDocument document, PDPage page, PDPageContentStream contentStream) throws IOException {
		// createFromFile is the easiest way with an image file
		// if you already have the image in a BufferedImage,
		// call LosslessFactory.createFromImage() instead

		PDImageXObject pdImage = PDImageXObject.createFromFileByContent(new File("D:\\jpg\\gougou.jpg"), document);

		// contentStream.drawImage(ximage, 20, 20 );
		// better method inspired by http://stackoverflow.com/a/22318681/535646
		// reduce this value if the image is too large
		float scale = 1f;
		contentStream.drawImage(pdImage, 20, 20, page.getBBox().getWidth() * scale, page.getBBox().getHeight() * scale);
		contentStream.restoreGraphicsState();
	}
}
